﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Runtime.InteropServices;
using TwainDotNet.Win32;

namespace TwainDotNet.TwainNative
{

    public class SysData
    {
        public static readonly bool is32x = (IntPtr.Size == 4);
    }

     [StructLayout(LayoutKind.Sequential, Pack = 2)]
    public class BITMAPINFOHEADER
    {
        public int biSize;
        public int biWidth;
        public int biHeight;
        public short biPlanes;
        public short biBitCount;
        public int biCompression;
        public int biSizeImage;
        public int biXPelsPerMeter;
        public int biYPelsPerMeter;
        public int biClrUsed;
        public int biClrImportant;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 2)]
    public class RGBQUAD
    {
        public byte rgbBlue;
        public byte rgbGreen;
        public byte rgbRed;
        public byte rgbReserved;
    }


    [StructLayout(LayoutKind.Sequential, Pack = 2)]    
    public struct TwainHandle
    {
        private IntPtr ptr;
        private int offset;
        private IntPtr lockptr;
        private static TwainHandle empty;
        public IntPtr Current
        {
            get
            {
                return ToPtr(this.lockptr, this.offset);
            }
        }
        public static IntPtr ToPtr(IntPtr ptr, int offset)
        {
            return new IntPtr((SysData.is32x ? ((long)ptr.ToInt32()) : ptr.ToInt64()) + offset);
        }
        public TwainHandle(IntPtr ptr)
        {
            this.ptr = ptr;
            this.offset = 0;
            this.lockptr = IntPtr.Zero;
        }
        public static TwainHandle Empty
        {
            get
            {
                return empty;
            }
        }
        public static implicit operator IntPtr(TwainHandle handle)
        {
            return handle.ptr;
        }
        public static implicit operator TwainHandle(IntPtr value)
        {
            TwainHandle empty = Empty;
            empty.ptr = value;
            return empty;
        }
        public void Alloc(int size)
        {
            this.ptr = Kernel32Native.GlobalAlloc(GlobalAllocFlags.Handle, size);
            this.offset = 0;
        }
        public IntPtr LockAndReturn()
        {
            this.lockptr = Kernel32Native.GlobalLock(this.ptr);
            this.offset = 0;
            return this.lockptr;
        }
        public bool Lock()
        {
            return (this.LockAndReturn() != IntPtr.Zero);
        }
        public void Unlock()
        {
            if (this.lockptr != IntPtr.Zero)
            {
                Kernel32Native.GlobalUnlock(this.ptr);
                this.lockptr = IntPtr.Zero;
                this.offset = 0;
            }
        }
        public void Free()
        {
            this.Unlock();
            if (this.ptr != IntPtr.Zero)
            {
                Kernel32Native.GlobalFree(this.ptr);
                this.ptr = IntPtr.Zero;
            }
        }
        public void WriteUInt8(byte value)
        {
            if (IntPtr.Zero != this.lockptr)
            {
                Marshal.WriteByte(this.lockptr, this.offset, value);
                this.offset += Marshal.SizeOf(value);
            }
        }
        public byte ReadUInt8()
        {
            byte structure = 0;
            while (IntPtr.Zero != this.lockptr)
            {
                structure = Marshal.ReadByte(this.lockptr, this.offset);
                this.offset += Marshal.SizeOf(structure);
                return structure;
            }
            return structure;
        }
        public void WriteInt8(sbyte value)
        {
            if (IntPtr.Zero != this.lockptr)
            {
                Marshal.WriteByte(this.lockptr, this.offset, Convert.ToByte(value));
                this.offset += Marshal.SizeOf(value);
            }
        }
        public sbyte ReadInt8()
        {
            sbyte structure = 0;
            while (IntPtr.Zero != this.lockptr)
            {
                structure = Convert.ToSByte(Marshal.ReadByte(this.lockptr, this.offset));
                this.offset += Marshal.SizeOf(structure);
                return structure;
            }
            return structure;
        }
        public void WriteInt16(short value)
        {
            if (IntPtr.Zero != this.lockptr)
            {
                Marshal.WriteInt16(this.lockptr, this.offset, value);
                this.offset += Marshal.SizeOf(value);
            }
        }
        public short ReadInt16()
        {
            short structure = 0;
            if (IntPtr.Zero != this.lockptr)
            {
                structure = Marshal.ReadInt16(this.lockptr, this.offset);
                this.offset += Marshal.SizeOf(structure);
            }
            return structure;
        }
        public void WriteUInt16(ushort value)
        {
            if (IntPtr.Zero != this.lockptr)
            {
                Marshal.WriteInt16(this.lockptr, this.offset, Convert.ToInt16(value));
                this.offset += Marshal.SizeOf(value);
            }
        }
        public ushort ReadUInt16()
        {
            ushort structure = 0;
            if (IntPtr.Zero != this.lockptr)
            {
                structure = (ushort)Marshal.ReadInt16(this.lockptr, this.offset);
                this.offset += Marshal.SizeOf(structure);
            }
            return structure;
        }
        public void WriteInt32(int value)
        {
            if (IntPtr.Zero != this.lockptr)
            {
                Marshal.WriteInt32(this.lockptr, this.offset, value);
                this.offset += Marshal.SizeOf(value);
            }
        }
        public int ReadInt32()
        {
            int structure = 0;
            while (IntPtr.Zero != this.lockptr)
            {
                structure = Marshal.ReadInt32(this.lockptr, this.offset);
                this.offset += Marshal.SizeOf(structure);
                return structure;
            }
            return structure;
        }
        public void WriteUInt32(uint value)
        {
            if (IntPtr.Zero != this.lockptr)
            {
                Marshal.WriteInt32(this.lockptr, this.offset, Convert.ToInt32(value));
                this.offset += Marshal.SizeOf(value);
            }
        }
        public uint ReadUInt32()
        {
            uint structure = 0;
            while (IntPtr.Zero != this.lockptr)
            {
                structure = (uint)Marshal.ReadInt32(this.lockptr, this.offset);
                this.offset += Marshal.SizeOf(structure);
                return structure;
            }
            return structure;
        }
        public Fix32 ReadFix32()
        {
            Fix32 tw_fix = new Fix32();
            tw_fix.Whole = this.ReadInt16();
            tw_fix.Frac = this.ReadUInt16();
            return tw_fix;
        }
        public void WriteFix32(Fix32 value)
        {
            this.WriteInt16(value.Whole);
            this.WriteUInt16(value.Frac);
        }
        public string ReadString()
        {
            ArrayList list;
            int num3;
            list = new ArrayList();
            byte num = 0;
            do
            {
                num = Marshal.ReadByte(this.lockptr, this.offset);
                this.offset++;
                list.Add(num);
            }
            while (num != 0);
            int count = list.Count;
            byte[] bytes = new byte[count];
            num3 = 0;
            while (num3 < count)
            {
                bytes[num3] = Convert.ToByte(list[num3]);
                num3++;
            }
            return Encoding.ASCII.GetString(bytes);
        }
        public string ReadString(int size)
        {
            byte[] buffer;
            string str = "";
            if (IntPtr.Zero != this.lockptr)
            {
                buffer = new byte[size];
                for (int i = 0; i < size; i++)
                {
                    buffer[i] = Marshal.ReadByte(this.lockptr, this.offset);
                    this.offset++;
                }
                buffer[size - 1] = 0;
                return Encoding.ASCII.GetString(buffer);
            }
            return str;
        }
        public void WriteString(string str, int size)
        {
            if (IntPtr.Zero != this.lockptr)
            {

                int num2;
                byte[] bytes = Encoding.ASCII.GetBytes(str);
                int num = Math.Min(bytes.Length, size - 1);

                for (num2 = 0; num2 < num; num2++)
                {
                    Marshal.WriteByte(this.lockptr, this.offset, bytes[num2]);
                    this.offset++;
                }
                for (int i = 0; i < (size - num); i++)
                {
                    Marshal.WriteByte(this.lockptr, this.offset, 0);
                    this.offset++;
                }
                bytes = null;
            }
            return;
        }
        public void WriteRange(CapabilityRangeValue value)
        {
            if (IntPtr.Zero != this.lockptr)
            {
                this.WriteUInt16((ushort)value.TwainTyp);
                this.WriteUInt32(value.MinValue);
                this.WriteUInt32(value.MaxValue);
                this.WriteUInt32(value.StepSize);
                this.WriteUInt32(value.DefaultValue);
                this.WriteUInt32(value.CurrentValue);
            }
        }
        public CapabilityRangeValue ReadRange()
        {
            return new CapabilityRangeValue { TwainTyp = (TwainType)this.ReadUInt16(), MinValue = this.ReadUInt32(), MaxValue = this.ReadUInt32(), StepSize = this.ReadUInt32(), DefaultValue = this.ReadUInt32(), CurrentValue = this.ReadUInt32() };
        }
        public void WriteBimapHeader(BITMAPINFOHEADER head)
        {
            this.WriteInt32(head.biSize);
            this.WriteInt32(head.biWidth);
            this.WriteInt32(head.biHeight);
            this.WriteInt16(head.biPlanes);
            this.WriteInt16(head.biBitCount);
            this.WriteInt32(head.biCompression);
            this.WriteInt32(head.biSizeImage);
            this.WriteInt32(head.biXPelsPerMeter);
            this.WriteInt32(head.biYPelsPerMeter);
            this.WriteInt32(head.biClrUsed);
            this.WriteInt32(head.biClrImportant);
        }
        public void WritePalete(RGBQUAD[] bmiColors, int biClrUsed)
        {
            int num = Math.Min(bmiColors.Length, biClrUsed);
            for (int i = 0; i < num; i++)
            {
                this.WriteUInt8(bmiColors[i].rgbBlue);
                this.WriteUInt8(bmiColors[i].rgbGreen);
                this.WriteUInt8(bmiColors[i].rgbRed);
                this.WriteUInt8(bmiColors[i].rgbReserved);
            }
        }
        static TwainHandle()
        {
            empty = new TwainHandle(IntPtr.Zero);
        }
    }

}
